using System;
using System.Text;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;

namespace ctsu.Admin.Forms
{
	
	public class PrintingUtils
	{
		private PrintDialog _pDlg;
		private PrintDocument _pDoc;
		private int _page;
		private int _startRow;		
		private DataTable _dtPrint;
		private DataView _dvPrint;		
		string[] _title;
		private Form _form;
		bool _landscape;

		public PrintingUtils()
		{
			
		}
		public PrintingUtils(DataTable dt, string[] title, Form form, bool landscape)
		{
			this._dtPrint = dt;
			this._title = title;
			this._form = form;
			_landscape = landscape;
		}

		public PrintingUtils(DataView dv, string[] title, Form form, bool landscape)
		{
			this._dvPrint = dv;
			this._title = title;
			this._form = form;
			_landscape = landscape;
		}

		public PrintingUtils(string[] title, Form form, bool landscape)
		{
			this._title = title;
			this._form = form;
			_landscape = landscape;
		}

		public bool Initialize()
		{
			int count  = 0;
			if(this._dtPrint != null)
				count = _dtPrint.Rows.Count;
			else
				count = _dvPrint.Count;

			if(count == 0)
				return false;

			this._pDoc = new PrintDocument();			
			this._pDoc.DefaultPageSettings.Landscape = _landscape;
			this._pDlg = new PrintDialog();
			this._pDlg.Document = this._pDoc;

			if(_pDlg.ShowDialog(this._form) == DialogResult.Cancel)
				return false;

			if(this._dtPrint != null)
				this._pDoc.PrintPage +=new PrintPageEventHandler(_pDoc_PrintPageDt);
			else
				this._pDoc.PrintPage +=new PrintPageEventHandler(_pDoc_PrintPageDv);

			_page = 1;
			_startRow = 0;
			this._pDoc.Print();

			return true;
		}

		public bool InitializeTemplate(int type)
		{			
			this._pDoc = new PrintDocument();			
			this._pDoc.DefaultPageSettings.Landscape = _landscape;
			this._pDlg = new PrintDialog();
			this._pDlg.Document = this._pDoc;

			if(_pDlg.ShowDialog(this._form) == DialogResult.Cancel)
				return false;

			this._pDoc.PrintPage +=new PrintPageEventHandler(_pDoc_PrintPageTemplate);
			
			_page = 1;
			_startRow = 0;
			this._pDoc.Print();
			return true;
		}

		private void _pDoc_PrintPageTemplate(object sender, PrintPageEventArgs e)
		{
			StringBuilder sb = new StringBuilder();
			Graphics gfx = e.Graphics;			
			float pageBottom = gfx.VisibleClipBounds.Height;
			float pageWidth = gfx.VisibleClipBounds.Width;			
			//float rightMargin = 0;
			float leftMargin = 25;  
			float topMargin = 25;
 			
			if(this._pDoc.DefaultPageSettings.Landscape)
			{
				leftMargin -= 15;
				pageWidth -= 10;
			}

			Font prntFont = new Font("Arial", 10);
			Font smallFont = new Font("Arial", 4);
			Font titleFont = new Font("Arial", 14, FontStyle.Bold);
			Font subTitleFont = new Font("Arial", 12);
			Font ColumnHeadFont = new Font("Arial",10,FontStyle.Bold);

			Pen pen = new Pen(Color.Black);

			//get the line height with some padding
			float lineHeight = prntFont.GetHeight(e.Graphics) + 2;
			//float adjLineHeight = 0;

			//set the drawing to the top left of the page
			float yPos = topMargin;
			float xPos = leftMargin;

			//print page #
			string page = "Page " + this._page + "  Date: " + DateTime.Today;
			PrintCenter(page, e, prntFont, pageBottom-lineHeight);

			int width = Convert.ToInt32(pageWidth);
			
			for(int i=0; i<=width; i+=10)
			{
				gfx.DrawString(i.ToString(),smallFont, Brushes.Black, (float)i, yPos);
			}

			int bottom = Convert.ToInt32(pageBottom);
			for(int i=0; i<bottom; i+=10)
			{
				gfx.DrawString(i.ToString(),smallFont, Brushes.Black, 0, i);
			}


		}

		private void _pDoc_PrintPageDt(object sender, PrintPageEventArgs e)
		{
			StringBuilder sb = new StringBuilder();
			Graphics gfx = e.Graphics;			
			float pageBottom = gfx.VisibleClipBounds.Height;
			float pageWidth = gfx.VisibleClipBounds.Width;			
			//float rightMargin = 0;
			float leftMargin = 25;  
			float topMargin = 25;
             			
			if(this._pDoc.DefaultPageSettings.Landscape)
			{
				leftMargin -= 15;
				pageWidth -= 10;
			}

			Font prntFont = new Font("Arial", 10);
			Font titleFont = new Font("Arial", 14, FontStyle.Bold);
			Font subTitleFont = new Font("Arial", 12);
			Font ColumnHeadFont = new Font("Arial",10,FontStyle.Bold);

			Pen pen = new Pen(Color.Black);

			//get the line height with some padding
			float lineHeight = prntFont.GetHeight(e.Graphics) + 2;
			float adjLineHeight = 0;

			//set the drawing to the top left of the page
			float yPos = topMargin;
			float xPos = leftMargin;

			//print page #
			string page = "Page " + this._page + "  Date: " + DateTime.Today;
			PrintCenter(page, e, prntFont, pageBottom-lineHeight);

			#region title
			//print title and subtitle
			if(this._page == 1)
			{
				Forms.PrintingUtils.PrintCenter(this._title[0], e, titleFont, yPos);				
				yPos += titleFont.GetHeight(e.Graphics);
				if(_title.Length >1)
				{
					for(int j=1; j<_title.Length;j++)
					{
						Forms.PrintingUtils.PrintCenter(this._title[j], e, subTitleFont, yPos);
						yPos += subTitleFont.GetHeight(e.Graphics) + 2;
					}
				}
			}
			else
			{
				Forms.PrintingUtils.PrintCenter(this._title[0] + " - continued", e, titleFont, yPos);				
				yPos += titleFont.GetHeight(e.Graphics);
				if(_title.Length >1)
				{
					for(int j=1; j<_title.Length;j++)
					{
						Forms.PrintingUtils.PrintCenter(this._title[j], e, subTitleFont, yPos);
						yPos += subTitleFont.GetHeight(e.Graphics) + 2;
					}
				}
			}
			yPos += lineHeight;
			#endregion title

			#region heading
			int[] colWidth = new int[this._dtPrint.Columns.Count];
			int[] colStart = new int[this._dtPrint.Columns.Count];
			int totWidth = 10;
			int i = 0;
			int width = 0;

			RectangleF rec = new RectangleF();
			gfx.FillRectangle(Brushes.LightBlue, leftMargin +1, yPos, pageWidth-(leftMargin+1), lineHeight);			
			gfx.DrawRectangle(Pens.Black, leftMargin, yPos, (pageWidth - (leftMargin+1)), lineHeight);
			
			foreach(DataColumn dc in this._dtPrint.Columns)
			{				
				colStart[i] = totWidth + (int)leftMargin + 2;

				width = 30 + Convert.ToInt32(dc.ExtendedProperties["Width"]);
				totWidth += width;
				colWidth[i] = width;


				Forms.PrintingUtils.SetRectangle(ref rec, colStart[i], yPos, lineHeight, colWidth[i]);
				gfx.DrawString(dc.Caption, ColumnHeadFont, Brushes.Black, rec);
				i++;				 
			}
			yPos += lineHeight;
			#endregion heading

			#region body
			//get the number of lines we can print
			int maxLines = (int)Math.Ceiling((double)((pageBottom - yPos)/lineHeight));
			maxLines -=2;
			int curLine = 0;
			
			StringFormat fmt = new StringFormat();
			fmt.Trimming = StringTrimming.EllipsisCharacter;

			DataRow dr;			
			int numLines = 0;			
			for(int row = _startRow; row < _dtPrint.Rows.Count; row++)
			{
				dr = _dtPrint.Rows[row];

				//get the field with most number of lines
				numLines = GetNumberLinesRow(dr,e.Graphics,prntFont,lineHeight, colWidth);	
				if(numLines == 0)
					numLines = 1;

				if(curLine + numLines >= maxLines)
				{					
					_startRow = row;
					this._page++;
					e.HasMorePages = true;
					return;
				}

				adjLineHeight = lineHeight*numLines;
				int j = 0;
				string sVal = "";
				foreach(DataColumn dc in this._dtPrint.Columns)
				{					
					SetRectangle(ref rec, colStart[j], yPos, adjLineHeight, colWidth[j]);
					switch (dc.DataType.ToString())
					{
						case "System.String":
							sVal = dr[dc.ColumnName].ToString().Trim();		
							break;
						case "System.Int32":
							sVal = dr[dc.ColumnName].ToString();
							break;
						case "System.DateTime":
							sVal = ((DateTime)dr[dc.ColumnName]).ToString("MM/dd/yyyy");
							break;
						case "System.Decimal":
							sVal = ((decimal)dr[dc.ColumnName]).ToString("#,###.##");
							break;
						case "System.Boolean":
							sVal = dr[dc.ColumnName].ToString();
							break;
					}					
					gfx.DrawString(sVal, prntFont, Brushes.Black, rec, fmt);
					j++;
				}

				gfx.DrawRectangle(Pens.Black, leftMargin, yPos, pageWidth-(leftMargin+1), adjLineHeight);
				yPos += adjLineHeight;
				curLine += numLines;				
			}
			#endregion body
		}

		private void _pDoc_PrintPageDv(object sender, PrintPageEventArgs e)
		{
			StringBuilder sb = new StringBuilder();
			Graphics gfx = e.Graphics;			
			float pageBottom = gfx.VisibleClipBounds.Height;
			float pageWidth = gfx.VisibleClipBounds.Width;			
			//float rightMargin = 0;
			float leftMargin = 25;  
			float topMargin = 25;
 			
			if(this._pDoc.DefaultPageSettings.Landscape)
			{
				leftMargin -= 15;
				pageWidth -= 10;
			}

			Font prntFont = new Font("Arial", 10);
			Font titleFont = new Font("Arial", 14, FontStyle.Bold);
			Font subTitleFont = new Font("Arial", 12);
			Font ColumnHeadFont = new Font("Arial",10,FontStyle.Bold);

			Pen pen = new Pen(Color.Black);

			//get the line height with some padding
			float lineHeight = prntFont.GetHeight(e.Graphics) + 2;
			float adjLineHeight = 0;

			//set the drawing to the top left of the page
			float yPos = topMargin;
			float xPos = leftMargin;

			//print page #
			string page = "Page " + this._page;
			PrintCenter(page, e, prntFont, pageBottom-lineHeight);

			#region title
			//print title and subtitle
			if(this._page == 1)
			{
				Forms.PrintingUtils.PrintCenter(this._title[0], e, titleFont, yPos);				
				yPos += titleFont.GetHeight(e.Graphics);
				if(_title.Length >1)
				{
					for(int j=1; j<_title.Length;j++)
					{
						Forms.PrintingUtils.PrintCenter(this._title[j], e, subTitleFont, yPos);
						yPos += subTitleFont.GetHeight(e.Graphics) + 2;
					}
				}
			}
			else
			{
				Forms.PrintingUtils.PrintCenter(this._title[0] + " - continued", e, titleFont, yPos);				
				yPos += titleFont.GetHeight(e.Graphics);
				if(_title.Length >1)
				{
					for(int j=1; j<_title.Length;j++)
					{
						Forms.PrintingUtils.PrintCenter(this._title[j], e, subTitleFont, yPos);
						yPos += subTitleFont.GetHeight(e.Graphics) + 2;
					}
				}
			}
			yPos += lineHeight;
			#endregion title

			#region heading
			 
			int[] colWidth = new int[this._dvPrint.Table.Columns.Count];
			int[] colStart = new int[this._dvPrint.Table.Columns.Count];
			int totWidth = 10;
			int i = 0;
			int width = 0;

			RectangleF rec = new RectangleF();
			gfx.FillRectangle(Brushes.LightBlue, leftMargin +1, yPos, pageWidth-(leftMargin+1), lineHeight);			
			gfx.DrawRectangle(Pens.Black, leftMargin, yPos, (pageWidth - (leftMargin+1)), lineHeight);
			
			foreach(DataColumn dc in this._dvPrint.Table.Columns)
			{				
				colStart[i] = totWidth + (int)leftMargin + 2;

				width = 30 + Convert.ToInt32(dc.ExtendedProperties["Width"]);
				totWidth += width;
				colWidth[i] = width;


				Forms.PrintingUtils.SetRectangle(ref rec, colStart[i], yPos, lineHeight, colWidth[i]);
				gfx.DrawString(dc.Caption, ColumnHeadFont, Brushes.Black, rec);
				i++;				 
			}
			yPos += lineHeight;
			#endregion heading

			#region body
			//get the number of lines we can print
			int maxLines = (int)Math.Ceiling((double)((pageBottom - yPos)/lineHeight));
			maxLines -=2;
			int curLine = 0;
			
			StringFormat fmt = new StringFormat();
			fmt.Trimming = StringTrimming.EllipsisCharacter;

			DataRowView drv;							
			int numLines = 0;			
			for(int row = _startRow; row < _dvPrint.Count; row++)
			{
				drv = _dvPrint[row];

				//get the field with most number of lines
				numLines = GetNumberLinesRow(drv,e.Graphics,prntFont,lineHeight, colWidth);
				if(numLines == 0)
					numLines = 1;

				if(curLine + numLines >= maxLines)
				{					
					_startRow = row;
					this._page++;
					e.HasMorePages = true;
					return;
				}

				adjLineHeight = lineHeight*numLines;
				int j = 0;
				string sVal = "";
				foreach(DataColumn dc in this._dvPrint.Table.Columns)
				{					
					SetRectangle(ref rec, colStart[j], yPos, adjLineHeight, colWidth[j]);
					switch (dc.DataType.ToString())
					{
						case "System.String":
							sVal = drv[dc.ColumnName].ToString().Trim();		
							break;
						case "System.Int32":
							sVal = drv[dc.ColumnName].ToString();
							break;
						case "System.DateTime":
							sVal = "";
							if(drv[dc.ColumnName] != System.DBNull.Value)
                                sVal = ((DateTime)drv[dc.ColumnName]).ToString("MM/dd/yyyy");
							break;
						case "System.Decimal":
							sVal = ((decimal)drv[dc.ColumnName]).ToString("#,###.##");
							break;
						case "System.Boolean":
							sVal = drv[dc.ColumnName].ToString();
							break;
					}					
					gfx.DrawString(sVal, prntFont, Brushes.Black, rec, fmt);
					j++;
				}

				gfx.DrawRectangle(Pens.Black, leftMargin, yPos, pageWidth-(leftMargin+1), adjLineHeight);
				yPos += adjLineHeight;
				curLine += numLines;				
			}
			#endregion body
		}

		public static void SetRectangle(ref RectangleF rec, float x, float y, float height, float width)
		{
			rec.X = x;
			rec.Y = y;
			rec.Height = height;
			rec.Width = width;
		}

		public static void PrintCenter(string s, PrintPageEventArgs e, Font font, float yPos)
		{
			float xPos = GetCenterXPos(s, e, font);
			e.Graphics.DrawString(s, font, Brushes.Black, xPos, yPos);
		}

		private static float GetCenterXPos(string s, PrintPageEventArgs e, Font font)
		{
			return((e.Graphics.VisibleClipBounds.Width/2 ) - (e.Graphics.MeasureString(s, font).Width / 2));
		}
		
		public static int GetNumberLines(string str, Graphics gfx, Font font, float colWidth, float maxColHeight, float oneLineHeight)
		{			
			int lines = 0;
			float thisLineHeight = 0;

			//if maxColHeight is 0 then a really hight number
			//is used virtually saying the max height is unlimited
			if(maxColHeight == 0)
				maxColHeight = 1000;

			//this is the size constaint the string will fit in
			SizeF szf = new SizeF(colWidth, maxColHeight);
			
			string[] sa = str.Split('\n');
 
			SizeF szS = new SizeF(0,0);
			foreach(string s in sa)
			{
				szS = gfx.MeasureString(s, font, szf);
				thisLineHeight = szS.Height;
				lines += (int)(Math.Ceiling(thisLineHeight/oneLineHeight));
			}

			return lines;
		}
		
		public static int GetNumberLinesRow(DataRow dr,Graphics gfx, Font font, float oneLineHeight, int[] colWidth)
		{
			int i=0;
			int numLines = 0;
			int mostLines = 0;
			string sVal = "";

			foreach(DataColumn dc in dr.Table.Columns)
			{				
				//only do strings
				if(dc.DataType == typeof(string))
				{
					sVal = dr[dc.ColumnName].ToString().Trim();
					numLines = Forms.PrintingUtils.GetNumberLines(sVal,gfx,font,colWidth[i],0,oneLineHeight);
					if(numLines > mostLines)
						mostLines = numLines;					
				}
				i++;
			}
			return mostLines;
		}

		public static int GetNumberLinesRow(DataRowView drv,Graphics gfx, Font font, float oneLineHeight, int[] colWidth)
		{
			int i=0;
			int numLines = 0;
			int mostLines = 0;
			string sVal = "";

			foreach(DataColumn dc in drv.DataView.Table.Columns)
			{				
				//only do strings
				if(dc.DataType == typeof(string))
				{
					sVal = drv[dc.ColumnName].ToString().Trim();
					numLines = Forms.PrintingUtils.GetNumberLines(sVal,gfx,font,colWidth[i],0,oneLineHeight);
					if(numLines > mostLines)
						mostLines = numLines;					
				}
				i++;
			}
			return mostLines;
		}
	}

	public class ReportPropertiesExtended
	{
		private string[] _header;
		private string[] _footer;

		public ReportPropertiesExtended(string[] header, string[] footer)
		{
			this._header = header;
			this._footer = footer;
		}

		public string[] Header
		{
			get{return _header;}
			set{_header = value;}
		}

		public string[] Footer
		{
			get{return _footer;}
			set{_footer = value;}
		}
	}
}
